package lpg;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

class Blocks
{
    BlockSymbol insertBlock(Token tokenLocation, BlockSymbol.Kind kind,
            ActionFileSymbol filenameSymbol, String blockBegin, String blockEnd)
    {
        BlockSymbol block = new BlockSymbol(blockBegin, blockTable.size());
        block.setLocation(tokenLocation);
        block.setKind(kind);
        block.setBlockEnd(blockEnd);
        block.setActionFileSymbol(filenameSymbol);
        blockTable.insert(blockBegin, block);
        switch (kind)
        {
            case MAIN_BLOCK:
                filenameSymbol.setBlock(block);
                break;
            case HEADER_BLOCK:
                block.setBuffer(filenameSymbol.getNextHeaderBuffer());
                break;
            case TRAILER_BLOCK:
                block.setBuffer(filenameSymbol.getNextTrailerBuffer());
                break;
            default:
                assert false;
        }

        char c = blockBegin.charAt(0);
        List<BlockSymbol> blockList = blockMap.get(c);
        if (blockList == null)
        {
            blockList = new ArrayList<BlockSymbol>();
            blockMap.put(c, blockList);
        }
        blockList.add(block);

        return block;
    }

    BlockSymbol findBlockname(String blockBegin)
    {
        return blockTable.find(blockBegin);
    }

    BlockSymbol findOrInsertIgnoredBlock(String blockBegin)
    {
        return ignoredTable.findOrInsert(blockBegin,
                new BlockSymbol(blockBegin, ignoredTable.size()));
    }

    boolean isIgnoredBlock(String blockBegin)
    {
        return ignoredTable.findKey(blockBegin) != null;
    }

    ActionFileSymbol findFilename(String name)
    {
        return filenameTable.find(name);
    }

    ActionFileSymbol findOrInsertFilename(String name)
    {
        return filenameTable.findOrInsert(name,
                new ActionFileSymbol(name, filenameTable.size()));
    }

    List<BlockSymbol> actionBlocks(char c)
    {
        return blockMap.get(c);
    }

    Collection<List<BlockSymbol>> actionBlocks()
    {
        return blockMap.values();
    }

    int numActionBlocks()
    {
        return blockTable.size();
    }

    BlockSymbol get(int i)
    {
        return blockTable.element(i);
    }

    void putNotice(StringBuilder noticeBuffer)
    {
        for (int i = 0, n = filenameTable.size(); i < n; i++)
        {
            filenameTable.element(i).initialHeadersBuffer().append(noticeBuffer);
        }
    }

    void flush()
    {
        for (int i = 0, n = filenameTable.size(); i < n; i++)
        {
            filenameTable.element(i).flush();
        }
    }

    private final Map<Character, List<BlockSymbol>> blockMap = new HashMap<Character, List<BlockSymbol>>();
    private final LookupTable<String, BlockSymbol> blockTable = new LookupTable<String, BlockSymbol>();
    private final LookupTable<String, BlockSymbol> ignoredTable = new LookupTable<String, BlockSymbol>();
    private final LookupTable<String, ActionFileSymbol> filenameTable = new LookupTable<String, ActionFileSymbol>();

}
